home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ddj0492.zip / DFLT11.ZIP / EDITBOX.C < prev    next >
Text File  |  1992-02-17  |  36KB  |  1,133 lines

  1. /* ------------- editbox.c ------------ */
  2. #include "dflat.h"
  3.  
  4. #define EditBufLen(wnd) (isMultiLine(wnd) ? EDITLEN : ENTRYLEN)
  5. #define SetLinePointer(wnd, ln) (wnd->CurrLine = ln)
  6. #define isWhite(c)     ((c)==' '||(c)=='\n')
  7. /* ---------- local prototypes ----------- */
  8. static void SaveDeletedText(WINDOW, char *, int);
  9. static void Forward(WINDOW);
  10. static void Backward(WINDOW);
  11. static void End(WINDOW);
  12. static void Home(WINDOW);
  13. static void Downward(WINDOW);
  14. static void Upward(WINDOW);
  15. static void StickEnd(WINDOW);
  16. static void NextWord(WINDOW);
  17. static void PrevWord(WINDOW);
  18. static void ModTextPointers(WINDOW, int, int);
  19. /* -------- local variables -------- */
  20. static BOOL KeyBoardMarking, ButtonDown;
  21. static BOOL TextMarking;
  22. static int ButtonX, ButtonY;
  23. static int PrevY = -1;
  24.  
  25. /* ----------- CREATE_WINDOW Message ---------- */
  26. static int CreateWindowMsg(WINDOW wnd)
  27. {
  28.     int rtn = BaseWndProc(EDITBOX, wnd, CREATE_WINDOW, 0, 0);
  29.     wnd->MaxTextLength = MAXTEXTLEN+1;
  30.     wnd->textlen = EditBufLen(wnd);
  31.     wnd->InsertMode = TRUE;
  32.     SendMessage(wnd, CLEARTEXT, 0, 0);
  33.     return rtn;
  34. }
  35. /* ----------- SETTEXT Message ---------- */
  36. static int SetTextMsg(WINDOW wnd, PARAM p1)
  37. {
  38.     int rtn = FALSE;
  39.     if (strlen((char *)p1) <= wnd->MaxTextLength)
  40.         rtn = BaseWndProc(EDITBOX, wnd, SETTEXT, p1, 0);
  41.     return rtn;
  42. }
  43. /* ----------- CLEARTEXT Message ------------ */
  44. static int ClearTextMsg(WINDOW wnd)
  45. {
  46.     int rtn = BaseWndProc(EDITBOX, wnd, CLEARTEXT, 0, 0);
  47.     unsigned blen = EditBufLen(wnd)+2;
  48.     wnd->text = realloc(wnd->text, blen);
  49.     memset(wnd->text, 0, blen);
  50.     wnd->wlines = 0;
  51.     wnd->CurrLine = 0;
  52.     wnd->CurrCol = 0;
  53.     wnd->WndRow = 0;
  54.     wnd->wleft = 0;
  55.     wnd->wtop = 0;
  56.     wnd->textwidth = 0;
  57.     wnd->TextChanged = FALSE;
  58.     return rtn;
  59. }
  60. /* ----------- ADDTEXT Message ---------- */
  61. static int AddTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  62. {
  63.     int rtn = FALSE;
  64.     if (strlen((char *)p1)+wnd->textlen <= wnd->MaxTextLength) {
  65.         rtn = BaseWndProc(EDITBOX, wnd, ADDTEXT, p1, p2);
  66.         if (rtn != FALSE)    {
  67.             if (!isMultiLine(wnd))    {
  68.                 wnd->CurrLine = 0;
  69.                 wnd->CurrCol = strlen((char *)p1);
  70.                 if (wnd->CurrCol >= ClientWidth(wnd))    {
  71.                     wnd->wleft = wnd->CurrCol-ClientWidth(wnd);
  72.                     wnd->CurrCol -= wnd->wleft;
  73.                 }
  74.                 wnd->BlkEndCol = wnd->CurrCol;
  75.                 SendMessage(wnd, KEYBOARD_CURSOR,
  76.                                      WndCol, wnd->WndRow);
  77.             }
  78.         }
  79.     }
  80.     return rtn;
  81. }
  82. /* ----------- GETTEXT Message ---------- */
  83. static int GetTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  84. {
  85.     char *cp1 = (char *)p1;
  86.     char *cp2 = wnd->text;
  87.     if (cp2 != NULL)    {
  88.         while (p2-- && *cp2 && *cp2 != '\n')
  89.             *cp1++ = *cp2++;
  90.         *cp1 = '\0';
  91.         return TRUE;
  92.     }
  93.     return FALSE;
  94. }
  95. /* ----------- SETTEXTLENGTH Message ---------- */
  96. static int SetTextLengthMsg(WINDOW wnd, unsigned int len)
  97. {
  98.     if (++len < MAXTEXTLEN)    {
  99.         wnd->MaxTextLength = len;
  100.         if (len < wnd->textlen)    {
  101.             if ((wnd->text=realloc(wnd->text, len+2)) != NULL) {
  102.                 wnd->textlen = len;
  103.                 *((wnd->text)+len) = '\0';
  104.                 *((wnd->text)+len+1) = '\0';
  105.                 BuildTextPointers(wnd);
  106.             }
  107.         }
  108.         return TRUE;
  109.     }
  110.     return FALSE;
  111. }
  112. /* ----------- KEYBOARD_CURSOR Message ---------- */
  113. static void KeyboardCursorMsg(WINDOW wnd, PARAM p1, PARAM p2)
  114. {
  115.     wnd->CurrCol = (int)p1 + wnd->wleft;
  116.     wnd->WndRow = (int)p2;
  117.     wnd->CurrLine = (int)p2 + wnd->wtop;
  118.     if (wnd == inFocus)    {
  119.         if (CharInView(wnd, (int)p1, (int)p2))
  120.             SendMessage(NULL, SHOW_CURSOR, wnd->InsertMode, 0);
  121.         else
  122.             SendMessage(NULL, HIDE_CURSOR, 0, 0);
  123.     }
  124. }
  125. /* ----------- SIZE Message ---------- */
  126. int SizeMsg(WINDOW wnd, PARAM p1, PARAM p2)
  127. {
  128.     int rtn = BaseWndProc(EDITBOX, wnd, SIZE, p1, p2);
  129.     if (WndCol > ClientWidth(wnd)-1)
  130.         wnd->CurrCol = ClientWidth(wnd)-1 + wnd->wleft;
  131.     if (wnd->WndRow > ClientHeight(wnd)-1)    {
  132.         wnd->WndRow = ClientHeight(wnd)-1;
  133.         SetLinePointer(wnd, wnd->WndRow+wnd->wtop);
  134.     }
  135.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  136.     return rtn;
  137. }
  138. /* ----------- SCROLL Message ---------- */
  139. static int ScrollMsg(WINDOW wnd, PARAM p1)
  140. {
  141.     int rtn = FALSE;
  142.     if (isMultiLine(wnd))    {
  143.         rtn = BaseWndProc(EDITBOX,wnd,SCROLL,p1,0);
  144.         if (rtn != FALSE)    {
  145.             if (p1)    {
  146.                 /* -------- scrolling up --------- */
  147.                 if (wnd->WndRow == 0)    {
  148.                     wnd->CurrLine++;
  149.                     StickEnd(wnd);
  150.                 }
  151.                 else
  152.                     --wnd->WndRow;
  153.             }
  154.             else    {
  155.                 /* -------- scrolling down --------- */
  156.                 if (wnd->WndRow == ClientHeight(wnd)-1)    {
  157.                     if (wnd->CurrLine > 0)
  158.                         --wnd->CurrLine;
  159.                     StickEnd(wnd);
  160.                 }
  161.                 else
  162.                     wnd->WndRow++;
  163.             }
  164.             SendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow);
  165.         }
  166.     }
  167.     return rtn;
  168. }
  169. /* ----------- HORIZSCROLL Message ---------- */
  170. static int HorizScrollMsg(WINDOW wnd, PARAM p1)
  171. {
  172.     int rtn = FALSE;
  173.     char *currchar = CurrChar;
  174.     if (!(p1 &&
  175.             wnd->CurrCol == wnd->wleft && *currchar == '\n'))  {
  176.         rtn = BaseWndProc(EDITBOX, wnd, HORIZSCROLL, p1, 0);
  177.         if (rtn != FALSE)    {
  178.             if (wnd->CurrCol < wnd->wleft)
  179.                 wnd->CurrCol++;
  180.             else if (WndCol == ClientWidth(wnd))
  181.                 --wnd->CurrCol;
  182.             SendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow);
  183.         }
  184.     }
  185.     return rtn;
  186. }
  187. /* ----------- SCROLLPAGE Message ---------- */
  188. static int ScrollPageMsg(WINDOW wnd, PARAM p1)
  189. {
  190.     int rtn = FALSE;
  191.     if (isMultiLine(wnd))    {
  192.         rtn = BaseWndProc(EDITBOX, wnd, SCROLLPAGE, p1, 0);
  193.         SetLinePointer(wnd, wnd->wtop+wnd->WndRow);
  194.         StickEnd(wnd);
  195.         SendMessage(wnd, KEYBOARD_CURSOR,WndCol, wnd->WndRow);
  196.     }
  197.     return rtn;
  198. }
  199. /* ----------- HORIZSCROLLPAGE Message ---------- */
  200. static int HorizPageMsg(WINDOW wnd, PARAM p1)
  201. {
  202.     int rtn = BaseWndProc(EDITBOX, wnd, HORIZPAGE, p1, 0);
  203.     if ((int) p1 == FALSE)    {
  204.         if (wnd->CurrCol > wnd->wleft+ClientWidth(wnd)-1)
  205.             wnd->CurrCol = wnd->wleft+ClientWidth(wnd)-1;
  206.     }
  207.     else if (wnd->CurrCol < wnd->wleft)
  208.         wnd->CurrCol = wnd->wleft;
  209.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  210.     return rtn;
  211. }
  212. /* ----- Extend the marked block to the new x,y position ---- */
  213. static void ExtendBlock(WINDOW wnd, int x, int y)
  214. {
  215.     int bbl, bel;
  216.     int ptop = min(wnd->BlkBegLine, wnd->BlkEndLine);
  217.     int pbot = max(wnd->BlkBegLine, wnd->BlkEndLine);
  218.     char *lp = TextLine(wnd, wnd->wtop+y);
  219.     int len = (int) (strchr(lp, '\n') - lp);
  220.     x = min(x, len-wnd->wleft);
  221.     wnd->BlkEndCol = x+wnd->wleft;
  222.     wnd->BlkEndLine = y+wnd->wtop;
  223.     bbl = min(wnd->BlkBegLine, wnd->BlkEndLine);
  224.     bel = max(wnd->BlkBegLine, wnd->BlkEndLine);
  225.     while (ptop < bbl)    {
  226.         WriteTextLine(wnd, NULL, ptop, FALSE);
  227.         ptop++;
  228.     }
  229.     for (y = bbl; y <= bel; y++)
  230.         WriteTextLine(wnd, NULL, y, FALSE);
  231.     while (pbot > bel)    {
  232.         WriteTextLine(wnd, NULL, pbot, FALSE);
  233.         --pbot;
  234.     }
  235. }
  236. /* ----------- LEFT_BUTTON Message ---------- */
  237. static int LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  238. {
  239.     int MouseX = (int) p1 - GetClientLeft(wnd);
  240.     int MouseY = (int) p2 - GetClientTop(wnd);
  241.     RECT rc = ClientRect(wnd);
  242.     char *lp;
  243.     int len;
  244.     if (KeyBoardMarking)
  245.         return TRUE;
  246.     if (WindowMoving || WindowSizing)
  247.         return FALSE;
  248.     if (isMultiLine(wnd))    {
  249.         if (TextMarking)    {
  250.             if (!InsideRect(p1, p2, rc))    {
  251.                 if ((int)p1 == GetLeft(wnd))
  252.                     if (SendMessage(wnd, HORIZSCROLL, 0, 0))
  253.                         ExtendBlock(wnd, MouseX-1, MouseY);
  254.                 if ((int)p1 == GetRight(wnd))
  255.                     if (SendMessage(wnd, HORIZSCROLL, TRUE, 0))
  256.                         ExtendBlock(wnd, MouseX+1, MouseY);
  257.                 if ((int)p2 == GetTop(wnd))
  258.                     if (SendMessage(wnd, SCROLL, FALSE, 0))
  259.                         ExtendBlock(wnd, MouseX, MouseY+1);
  260.                 if ((int)p2 == GetBottom(wnd))
  261.                     if (SendMessage(wnd, SCROLL, TRUE, 0))
  262.                         ExtendBlock(wnd, MouseX, MouseY-1);
  263.                 SendMessage(wnd, PAINT, 0, 0);
  264.             }
  265.             return TRUE;
  266.         }
  267.         if (!InsideRect(p1, p2, rc))
  268.             return FALSE;
  269.         if (TextBlockMarked(wnd))    {
  270.             ClearTextBlock(wnd);
  271.             SendMessage(wnd, PAINT, 0, 0);
  272.         }
  273.         if (wnd->wlines)    {
  274.             if (MouseY > wnd->wlines-1)
  275.                 return TRUE;
  276.             lp = TextLine(wnd, MouseY+wnd->wtop);
  277.             len = (int) (strchr(lp, '\n') - lp);
  278.             MouseX = min(MouseX, len);
  279.             if (MouseX < wnd->wleft)    {
  280.                 MouseX = 0;
  281.                 SendMessage(wnd, KEYBOARD, HOME, 0);
  282.             }
  283.             ButtonDown = TRUE;
  284.             ButtonX = MouseX;
  285.             ButtonY = MouseY;
  286.         }
  287.         else
  288.             MouseX = MouseY = 0;
  289.         wnd->WndRow = MouseY;
  290.         SetLinePointer(wnd, MouseY+wnd->wtop);
  291.     }
  292.     if (isMultiLine(wnd) ||
  293.         (!TextBlockMarked(wnd)
  294.             && MouseX+wnd->wleft < strlen(wnd->text)))
  295.         wnd->CurrCol = MouseX+wnd->wleft;
  296.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  297.     return TRUE;
  298. }
  299. /* ----------- MOUSE_MOVED Message ---------- */
  300. static int MouseMovedMsg(WINDOW wnd, PARAM p1, PARAM p2)
  301. {
  302.     int MouseX = (int) p1 - GetClientLeft(wnd);
  303.     int MouseY = (int) p2 - GetClientTop(wnd);
  304.     RECT rc = ClientRect(wnd);
  305.     if (!InsideRect(p1, p2, rc))
  306.         return FALSE;
  307.     if (MouseY > wnd->wlines-1)
  308.         return FALSE;
  309.     if (ButtonDown)    {
  310.         SetAnchor(wnd, ButtonX+wnd->wleft, ButtonY+wnd->wtop);
  311.         TextMarking = TRUE;
  312.         rc = WindowRect(wnd);
  313.         SendMessage(NULL,MOUSE_TRAVEL,(PARAM) &rc, 0);
  314.         ButtonDown = FALSE;
  315.     }
  316.     if (TextMarking && !(WindowMoving || WindowSizing))    {
  317.         ExtendBlock(wnd, MouseX, MouseY);
  318.         return TRUE;
  319.     }
  320.     return FALSE;
  321. }
  322. static void StopMarking(WINDOW wnd)
  323. {
  324.     TextMarking = FALSE;
  325.     if (wnd->BlkBegLine > wnd->BlkEndLine)    {
  326.         swap(wnd->BlkBegLine, wnd->BlkEndLine);
  327.         swap(wnd->BlkBegCol, wnd->BlkEndCol);
  328.     }
  329.     if (wnd->BlkBegLine == wnd->BlkEndLine &&
  330.             wnd->BlkBegCol > wnd->BlkEndCol)
  331.         swap(wnd->BlkBegCol, wnd->BlkEndCol);
  332. }
  333. /* ----------- BUTTON_RELEASED Message ---------- */
  334. static int ButtonReleasedMsg(WINDOW wnd)
  335. {
  336.     if (isMultiLine(wnd))    {
  337.         ButtonDown = FALSE;
  338.         if (TextMarking && !(WindowMoving || WindowSizing))  {
  339.             /* release the mouse ouside the edit box */
  340.             SendMessage(NULL, MOUSE_TRAVEL, 0, 0);
  341.             StopMarking(wnd);
  342.             return TRUE;
  343.         }
  344.         else
  345.             PrevY = -1;
  346.     }
  347.     return FALSE;
  348. }
  349. /* ---- Process text block keys for multiline text box ---- */
  350. static void DoMultiLines(WINDOW wnd, int c, PARAM p2)
  351. {
  352.     if (isMultiLine(wnd))    {
  353.         if ((int)p2 & (LEFTSHIFT | RIGHTSHIFT))    {
  354.             int kx, ky;
  355.             SendMessage(NULL, CURRENT_KEYBOARD_CURSOR,
  356.                 (PARAM) &kx, (PARAM) &ky);
  357.             kx -= GetClientLeft(wnd);
  358.             ky -= GetClientTop(wnd);
  359.             switch (c)    {
  360.                 case HOME:
  361.                 case END:
  362.                 case CTRL_HOME:
  363.                 case CTRL_END:
  364.                 case PGUP:
  365.                 case PGDN:
  366.                 case CTRL_PGUP:
  367.                 case CTRL_PGDN:
  368.                 case UP:
  369.                 case DN:
  370.                 case FWD:
  371.                 case BS:
  372.                 case CTRL_FWD:
  373.                 case CTRL_BS:
  374.                     if (!KeyBoardMarking)    {
  375.                         if (TextBlockMarked(wnd))    {
  376.                             ClearTextBlock(wnd);
  377.                             SendMessage(wnd, PAINT, 0, 0);
  378.                         }
  379.                         KeyBoardMarking = TextMarking = TRUE;
  380.                         SetAnchor(wnd, kx+wnd->wleft,
  381.                                                 ky+wnd->wtop);
  382.                     }
  383.                     break;
  384.                 default:
  385.                     break;
  386.             }
  387.         }
  388.     }
  389. }
  390. /* ---------- page/scroll keys ----------- */
  391. static int DoScrolling(WINDOW wnd, int c, PARAM p2)
  392. {
  393.     switch (c)    {
  394.         case PGUP:
  395.         case PGDN:
  396.             if (isMultiLine(wnd))
  397.                 BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2);
  398.             break;
  399.         case CTRL_PGUP:
  400.         case CTRL_PGDN:
  401.             BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2);
  402.             break;
  403.         case HOME:
  404.             Home(wnd);
  405.             break;
  406.         case END:
  407.             End(wnd);
  408.             break;
  409.         case CTRL_FWD:
  410.             NextWord(wnd);
  411.             break;
  412.         case CTRL_BS:
  413.             PrevWord(wnd);
  414.             break;
  415.         case CTRL_HOME:
  416.             if (isMultiLine(wnd))    {
  417.                 SendMessage(wnd, SCROLLDOC, TRUE, 0);
  418.                 wnd->CurrLine = 0;
  419.                 wnd->WndRow = 0;
  420.             }
  421.             Home(wnd);
  422.             break;
  423.         case CTRL_END:
  424.             if (isMultiLine(wnd) &&
  425.                     wnd->WndRow+wnd->wtop+1 < wnd->wlines
  426.                         && wnd->wlines > 0) {
  427.                 SendMessage(wnd, SCROLLDOC, FALSE, 0);
  428.                 SetLinePointer(wnd, wnd->wlines-1);
  429.                 wnd->WndRow =
  430.                     min(ClientHeight(wnd)-1, wnd->wlines-1);
  431.                 Home(wnd);
  432.             }
  433.             End(wnd);
  434.             break;
  435.         case UP:
  436.             if (isMultiLine(wnd))
  437.                 Upward(wnd);
  438.             break;
  439.         case DN:
  440.             if (isMultiLine(wnd))
  441.                 Downward(wnd);
  442.             break;
  443.         case FWD:
  444.             Forward(wnd);
  445.             break;
  446.         case BS:
  447.             Backward(wnd);
  448.             break;
  449.         default:
  450.             return FALSE;
  451.     }
  452.     if (!KeyBoardMarking && TextBlockMarked(wnd))    {
  453.         ClearTextBlock(wnd);
  454.         SendMessage(wnd, PAINT, 0, 0);
  455.     }
  456.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  457.     return TRUE;
  458. }
  459. /* -------------- Del key ---------------- */
  460. static void DelKey(WINDOW wnd)
  461. {
  462.     char *currchar = CurrChar;
  463.     int repaint = *currchar == '\n';
  464.     if (TextBlockMarked(wnd))    {
  465.         SendMessage(wnd, COMMAND, ID_DELETETEXT, 0);
  466.         SendMessage(wnd, PAINT, 0, 0);
  467.         return;
  468.     }
  469.     if (isMultiLine(wnd) && *(currchar+1) == '\0')
  470.         return;
  471.     strcpy(currchar, currchar+1);
  472.     if (repaint)    {
  473.         BuildTextPointers(wnd);
  474.         SendMessage(wnd, PAINT, 0, 0);
  475.     }
  476.     else    {
  477.         ModTextPointers(wnd, wnd->CurrLine+1, -1);
  478.         WriteTextLine(wnd, NULL, wnd->WndRow+wnd->wtop, FALSE);
  479.     }
  480.     wnd->TextChanged = TRUE;
  481. }
  482. /* ------------ Tab key ------------ */
  483. static void TabKey(WINDOW wnd, PARAM p2)
  484. {
  485.     if (isMultiLine(wnd))    {
  486.         int insmd = wnd->InsertMode;
  487.         do  {
  488.             char *cc = CurrChar+1;
  489.             if (!insmd && *cc == '\0')
  490.                 break;
  491.             if (wnd->textlen == wnd->MaxTextLength)
  492.                 break;
  493.             SendMessage(wnd,KEYBOARD,insmd ? ' ' : FWD,0);
  494.         } while (wnd->CurrCol % cfg.Tabs);
  495.     }
  496.     else
  497.         PostMessage(GetParent(wnd), KEYBOARD, '\t', p2);
  498. }
  499. /* ------------ Shift+Tab key ------------ */
  500. static void ShiftTabKey(WINDOW wnd, PARAM p2)
  501. {
  502.     if (isMultiLine(wnd))    {
  503.         do  {
  504.             if (CurrChar == GetText(wnd))
  505.                 break;
  506.             SendMessage(wnd,KEYBOARD,BS,0);
  507.         } while (wnd->CurrCol % cfg.Tabs);
  508.     }
  509.     else
  510.         PostMessage(GetParent(wnd), KEYBOARD, SHIFT_HT, p2);
  511. }
  512. /* --------- All displayable typed keys ------------- */
  513. static void KeyTyped(WINDOW wnd, int c)
  514. {
  515.     char *currchar = CurrChar;
  516.     if ((c != '\n' && c < ' ') || (c & 0x1000))
  517.         /* ---- not recognized by editor --- */
  518.         return;
  519.     if (!isMultiLine(wnd) && TextBlockMarked(wnd))    {
  520.         SendMessage(wnd, CLEARTEXT, 0, 0);
  521.         currchar = CurrChar;
  522.     }
  523.     /* ---- test typing at end of text ---- */
  524.     if (currchar == wnd->text+wnd->MaxTextLength)    {
  525.         /* ---- typing at the end of maximum buffer ---- */
  526.         beep();
  527.         return;
  528.     }
  529.     if (*currchar == '\0')    {
  530.         /* --- insert a newline at end of text --- */
  531.         *currchar = '\n';
  532.         *(currchar+1) = '\0';
  533.         BuildTextPointers(wnd);
  534.     }
  535.     /* --- displayable char or newline --- */
  536.     if (c == '\n' || wnd->InsertMode || *currchar == '\n') {
  537.         /* ------ inserting the keyed character ------ */
  538.         if (wnd->text[wnd->textlen-1] != '\0')    {
  539.             /* --- the current text buffer is full --- */
  540.             if (wnd->textlen == wnd->MaxTextLength)    {
  541.                 /* --- text buffer is at maximum size --- */
  542.                 beep();
  543.                 return;
  544.             }
  545.             /* ---- increase the text buffer size ---- */
  546.             wnd->textlen += GROWLENGTH;
  547.             /* --- but not above maximum size --- */
  548.             if (wnd->textlen > wnd->MaxTextLength)
  549.                 wnd->textlen = wnd->MaxTextLength;
  550.             wnd->text = realloc(wnd->text, wnd->textlen+2);
  551.             wnd->text[wnd->textlen-1] = '\0';
  552.             currchar = CurrChar;
  553.         }
  554.         memmove(currchar+1, currchar, strlen(currchar)+1);
  555.         ModTextPointers(wnd, wnd->CurrLine+1, 1);
  556.         if (isMultiLine(wnd) && wnd->wlines > 1)
  557.             wnd->textwidth = max(wnd->textwidth,
  558.                 (int) (TextLine(wnd, wnd->CurrLine+1)-
  559.                 TextLine(wnd, wnd->CurrLine)));
  560.         else
  561.             wnd->textwidth = max(wnd->textwidth,
  562.                 strlen(wnd->text));
  563.         WriteTextLine(wnd, NULL,
  564.             wnd->wtop+wnd->WndRow, FALSE);
  565.     }
  566.     /* ----- put the char in the buffer ----- */
  567.     *currchar = c;
  568.     wnd->TextChanged = TRUE;
  569.     if (c == '\n')    {
  570.         wnd->wleft = 0;
  571.         BuildTextPointers(wnd);
  572.         End(wnd);
  573.         Forward(wnd);
  574.         SendMessage(wnd, PAINT, 0, 0);
  575.         return;
  576.     }
  577.     /* ---------- test end of window --------- */
  578.     if (WndCol == ClientWidth(wnd)-1)    {
  579.         if (!isMultiLine(wnd))    {
  580.                 if (!(currchar == wnd->text+wnd->MaxTextLength-2))
  581.                 SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  582.         }
  583.         else    {
  584.             char *cp = currchar;
  585.             while (*cp != ' ' && cp != TextLine(wnd, wnd->CurrLine))
  586.                 --cp;
  587.             if (cp == TextLine(wnd, wnd->CurrLine) ||
  588.                     !wnd->WordWrapMode)
  589.                 SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  590.             else    {
  591.                 int dif = 0;
  592.                 if (c != ' ')    {
  593.                     dif = (int) (currchar - cp);
  594.                     wnd->CurrCol -= dif;
  595.                     SendMessage(wnd, KEYBOARD, DEL, 0);
  596.                     --dif;
  597.                 }
  598.                 SendMessage(wnd, KEYBOARD, '\r', 0);
  599.                 currchar = CurrChar;
  600.                 wnd->CurrCol = dif;
  601.                 if (c == ' ')
  602.                     return;
  603.             }
  604.         }
  605.     }
  606.     /* ------ display the character ------ */
  607.     SetStandardColor(wnd);
  608.     PutWindowChar(wnd, c, WndCol, wnd->WndRow);
  609.     /* ----- advance the pointers ------ */
  610.     wnd->CurrCol++;
  611. }
  612. /* ------------ screen changing key strokes ------------- */
  613. static void DoKeyStroke(WINDOW wnd, int c, PARAM p2)
  614. {
  615.     switch (c)    {
  616.         case RUBOUT:
  617.             if (wnd->CurrCol == 0 && wnd->CurrLine == 0)
  618.                 break;
  619.             Backward(wnd);
  620.         case DEL:
  621.             DelKey(wnd);
  622.             break;
  623.         case SHIFT_HT:
  624.             ShiftTabKey(wnd, p2);
  625.             break;
  626.         case '\t':
  627.             TabKey(wnd, p2);
  628.             break;
  629.         case '\r':
  630.             if (!isMultiLine(wnd))    {
  631.                 PostMessage(GetParent(wnd), KEYBOARD, c, p2);
  632.                 break;
  633.             }
  634.             c = '\n';
  635.         default:
  636.             if (TextBlockMarked(wnd))    {
  637.                 SendMessage(wnd, COMMAND, ID_DELETETEXT, 0);
  638.                 SendMessage(wnd, PAINT, 0, 0);
  639.             }
  640.             KeyTyped(wnd, c);
  641.             break;
  642.     }
  643. }
  644. /* ----------- KEYBOARD Message ---------- */
  645. static int KeyboardMsg(WINDOW wnd, PARAM p1, PARAM p2)
  646. {
  647.     int c = (int) p1;
  648.     if (WindowMoving || WindowSizing || ((int)p2 & ALTKEY))
  649.         return FALSE;
  650.     switch (c)    {
  651.         /* --- these keys get processed by lower classes --- */
  652.         case ESC:
  653.         case F1:
  654.         case F2:
  655.         case F3:
  656.         case F4:
  657.         case F5:
  658.         case F6:
  659.         case F7:
  660.         case F8:
  661.         case F9:
  662.         case F10:
  663.         case INS:
  664.         case SHIFT_INS:
  665.         case SHIFT_DEL:
  666.             return FALSE;
  667.         /* --- these keys get processed here --- */
  668.         case CTRL_FWD:
  669.         case CTRL_BS:
  670.         case CTRL_HOME:
  671.         case CTRL_END:
  672.         case CTRL_PGUP:
  673.         case CTRL_PGDN:
  674.             break;
  675.         default:
  676.             /* other ctrl keys get processed by lower classes */
  677.             if ((int)p2 & CTRLKEY)
  678.                 return FALSE;
  679.             /* --- all other keys get processed here --- */
  680.             break;
  681.     }
  682.     DoMultiLines(wnd, c, p2);
  683.     if (DoScrolling(wnd, c, p2))    {
  684.         if (KeyBoardMarking)
  685.             ExtendBlock(wnd, WndCol, wnd->WndRow);
  686.     }
  687.     else if (!TestAttribute(wnd, READONLY))    {
  688.         DoKeyStroke(wnd, c, p2);
  689.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  690.     }
  691.     return TRUE;
  692. }
  693. /* ----------- SHIFT_CHANGED Message ---------- */
  694. static void ShiftChangedMsg(WINDOW wnd, PARAM p1)
  695. {
  696.     if (!((int)p1 & (LEFTSHIFT | RIGHTSHIFT)) &&
  697.                                    KeyBoardMarking)    {
  698.         StopMarking(wnd);
  699.         KeyBoardMarking = FALSE;
  700.     }
  701. }
  702. /* ----------- ID_DELETETEXT Command ---------- */
  703. static void DeleteTextCmd(WINDOW wnd)
  704. {
  705.     if (TextBlockMarked(wnd))    {
  706.         char *bbl=TextLine(wnd,wnd->BlkBegLine)+wnd->BlkBegCol;
  707.         char *bel=TextLine(wnd,wnd->BlkEndLine)+wnd->BlkEndCol;
  708.         int len = (int) (bel - bbl);
  709.         SaveDeletedText(wnd, bbl, len);
  710.         wnd->TextChanged = TRUE;
  711.         strcpy(bbl, bel);
  712.         wnd->CurrLine = TextLineNumber(wnd, bbl-wnd->BlkBegCol);
  713.         wnd->CurrCol = wnd->BlkBegCol;
  714.         wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  715.         if (wnd->WndRow < 0)    {
  716.             wnd->wtop = wnd->BlkBegLine;
  717.             wnd->WndRow = 0;
  718.         }
  719.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  720.         ClearTextBlock(wnd);
  721.         BuildTextPointers(wnd);
  722.     }
  723. }
  724. /* ----------- ID_CLEAR Command ---------- */
  725. static void ClearCmd(WINDOW wnd)
  726. {
  727.     if (TextBlockMarked(wnd))    {
  728.         char *bbl=TextLine(wnd,wnd->BlkBegLine)+wnd->BlkBegCol;
  729.         char *bel=TextLine(wnd,wnd->BlkEndLine)+wnd->BlkEndCol;
  730.         int len = (int) (bel - bbl);
  731.         SaveDeletedText(wnd, bbl, len);
  732.         wnd->CurrLine = TextLineNumber(wnd, bbl);
  733.         wnd->CurrCol = wnd->BlkBegCol;
  734.         wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  735.         if (wnd->WndRow < 0)    {
  736.             wnd->WndRow = 0;
  737.             wnd->wtop = wnd->BlkBegLine;
  738.         }
  739.         /* ------ change all text lines in block to \n ----- */
  740.         while (bbl < bel)    {
  741.             char *cp = strchr(bbl, '\n');
  742.             if (cp > bel)
  743.                 cp = bel;
  744.             strcpy(bbl, cp);
  745.             bel -= (int) (cp - bbl);
  746.             bbl++;
  747.         }
  748.         ClearTextBlock(wnd);
  749.         BuildTextPointers(wnd);
  750.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  751.         SendMessage(wnd, PAINT, 0, 0);
  752.         wnd->TextChanged = TRUE;
  753.     }
  754. }
  755. /* ----------- ID_UNDO Command ---------- */
  756. static void UndoCmd(WINDOW wnd)
  757. {
  758.     if (wnd->DeletedText != NULL)    {
  759.         PasteText(wnd, wnd->DeletedText, wnd->DeletedLength);
  760.         free(wnd->DeletedText);
  761.         wnd->DeletedText = NULL;
  762.         wnd->DeletedLength = 0;
  763.         SendMessage(wnd, PAINT, 0, 0);
  764.     }
  765. }
  766. /* ----------- ID_PARAGRAPH Command ---------- */
  767. static void ParagraphCmd(WINDOW wnd)
  768. {
  769.     int bc, ec, fl, el, Blocked;
  770.     char *bl, *bbl, *bel, *bb;
  771.  
  772.     if (!TextBlockMarked(wnd))    {
  773.         Blocked = FALSE;
  774.         /* ---- forming paragraph from cursor position --- */
  775.         fl = wnd->wtop + wnd->WndRow;
  776.         bbl = bel = bl = TextLine(wnd, wnd->CurrLine);
  777.         if ((bc = wnd->CurrCol) >= ClientWidth(wnd))
  778.             bc = 0;
  779.         Home(wnd);
  780.         /* ---- locate the end of the paragraph ---- */
  781.         while (*bel)    {
  782.             int blank = TRUE;
  783.             char *bll = bel;
  784.             /* --- blank line marks end of paragraph --- */
  785.             while (*bel && *bel != '\n')    {
  786.                 if (*bel != ' ')
  787.                     blank = FALSE;
  788.                 bel++;
  789.             }
  790.             if (blank)    {
  791.                 bel = bll;
  792.                 break;
  793.             }
  794.             if (*bel)
  795.                 bel++;
  796.         }
  797.         if (bel == bbl)    {
  798.             SendMessage(wnd, KEYBOARD, DN, 0);
  799.             return;
  800.         }
  801.         if (*bel == '\0')
  802.             --bel;
  803.         if (*bel == '\n')
  804.             --bel;
  805.     }
  806.     else    {
  807.         /* ---- forming paragraph from marked block --- */
  808.         Blocked = TRUE;
  809.         el = wnd->BlkEndLine;
  810.         ec = wnd->BlkEndCol;
  811.         bbl = TextLine(wnd, wnd->BlkBegLine) + wnd->BlkBegCol;
  812.         bel = TextLine(wnd, wnd->BlkEndLine) + wnd->BlkEndCol;
  813.         fl = wnd->CurrLine = wnd->BlkBegLine;
  814.         bc = wnd->CurrCol = wnd->BlkBegCol;
  815.         if (fl < wnd->wtop)
  816.             wnd->wtop = fl;
  817.         wnd->WndRow = fl - wnd->wtop;
  818.         SendMessage(wnd, KEYBOARD, '\r', 0);
  819.         el++, fl++;
  820.         if (bc != 0)    {
  821.             SendMessage(wnd, KEYBOARD, '\r', 0);
  822.             el++, fl ++;
  823.         }
  824.         bc = 0;
  825.         bl = TextLine(wnd, fl);
  826.         wnd->CurrLine = fl;
  827.         bbl = bl + bc;
  828.         bel = TextLine(wnd, el) + ec;
  829.     }
  830.     /* --- change all newlines in block to spaces --- */
  831.     while (CurrChar < bel)    {
  832.         if (*CurrChar == '\n')    {
  833.             *CurrChar = ' ';
  834.             wnd->CurrLine++;
  835.             wnd->CurrCol = 0;
  836.         }
  837.         else
  838.             wnd->CurrCol++;
  839.     }
  840.     /* ---- insert newlines at new margin boundaries ---- */
  841.     bb = bbl;
  842.     while (bbl < bel)    {
  843.         bbl++;
  844.         if ((int)(bbl - bb) == ClientWidth(wnd)-1)    {
  845.             while (*bbl != ' ' && bbl > bb)
  846.                 --bbl;
  847.             if (*bbl != ' ')    {
  848.                 bbl = strchr(bbl, ' ');
  849.                 if (bbl == NULL || bbl >= bel)
  850.                     break;
  851.             }
  852.             *bbl = '\n';
  853.             bb = bbl+1;
  854.         }
  855.     }
  856.     ec = (int)(bel - bb);
  857.     BuildTextPointers(wnd);
  858.     if (Blocked)    {
  859.         /* ---- position cursor at end of new paragraph ---- */
  860.         if (el < wnd->wtop ||
  861.                 wnd->wtop + ClientHeight(wnd) < el)
  862.             wnd->wtop = el-ClientHeight(wnd);
  863.         if (wnd->wtop < 0)
  864.             wnd->wtop = 0;
  865.         wnd->WndRow = el - wnd->wtop;
  866.         wnd->CurrLine = el;
  867.         wnd->CurrCol = ec;
  868.         SendMessage(wnd, KEYBOARD, '\r', 0);
  869.         SendMessage(wnd, KEYBOARD, '\r', 0);
  870.     }
  871.     else    {
  872.         /* --- put cursor back at beginning --- */
  873.         wnd->CurrLine = TextLineNumber(wnd, bl);
  874.         wnd->CurrCol = bc;
  875.         if (fl < wnd->wtop)
  876.             wnd->wtop = fl;
  877.         wnd->WndRow = fl - wnd->wtop;
  878.     }
  879.     SendMessage(wnd, PAINT, 0, 0);
  880.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  881.     wnd->TextChanged = TRUE;
  882.     BuildTextPointers(wnd);
  883. }
  884. /* ----------- COMMAND Message ---------- */
  885. static int CommandMsg(WINDOW wnd, PARAM p1)
  886. {
  887.     switch ((int)p1)    {
  888.         case ID_DELETETEXT:
  889.             DeleteTextCmd(wnd);
  890.             return TRUE;
  891.         case ID_CLEAR:
  892.             ClearCmd(wnd);
  893.             return TRUE;
  894.         case ID_UNDO:
  895.             UndoCmd(wnd);
  896.             return TRUE;
  897.         case ID_PARAGRAPH:
  898.             ParagraphCmd(wnd);
  899.             return TRUE;
  900.         default:
  901.             break;
  902.     }
  903.     return FALSE;
  904. }
  905. /* ---------- CLOSE_WINDOW Message ----------- */
  906. static void CloseWindowMsg(WINDOW wnd)
  907. {
  908.     SendMessage(NULL, HIDE_CURSOR, 0, 0);
  909.     if (wnd->DeletedText != NULL)
  910.         free(wnd->DeletedText);
  911. }
  912. /* ------- Window processing module for EDITBOX class ------ */
  913. int EditBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  914. {
  915.     int rtn;
  916.     switch (msg)    {
  917.         case CREATE_WINDOW:
  918.             return CreateWindowMsg(wnd);
  919.         case ADDTEXT:
  920.             return AddTextMsg(wnd, p1, p2);
  921.         case SETTEXT:
  922.             return SetTextMsg(wnd, p1);
  923.         case CLEARTEXT:
  924.             return ClearTextMsg(wnd);
  925.         case GETTEXT:
  926.             return GetTextMsg(wnd, p1, p2);
  927.         case SETTEXTLENGTH:
  928.             return SetTextLengthMsg(wnd, (unsigned) p1);
  929.         case KEYBOARD_CURSOR:
  930.             KeyboardCursorMsg(wnd, p1, p2);
  931.             return TRUE;
  932.         case SETFOCUS:
  933.             if (!(int)p1)
  934.                 SendMessage(NULL, HIDE_CURSOR, 0, 0);
  935.         case PAINT:
  936.         case MOVE:
  937.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  938.             SendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow);
  939.             return rtn;
  940.         case SIZE:
  941.             return SizeMsg(wnd, p1, p2);
  942.         case SCROLL:
  943.             return ScrollMsg(wnd, p1);
  944.         case HORIZSCROLL:
  945.             return HorizScrollMsg(wnd, p1);
  946.         case SCROLLPAGE:
  947.             return ScrollPageMsg(wnd, p1);
  948.         case HORIZPAGE:
  949.             return HorizPageMsg(wnd, p1);
  950.         case LEFT_BUTTON:
  951.             if (LeftButtonMsg(wnd, p1, p2))
  952.                 return TRUE;
  953.             break;
  954.         case MOUSE_MOVED:
  955.             if (MouseMovedMsg(wnd, p1, p2))
  956.                 return TRUE;
  957.             break;
  958.         case BUTTON_RELEASED:
  959.             if (ButtonReleasedMsg(wnd))
  960.                 return TRUE;
  961.             break;
  962.         case KEYBOARD:
  963.             if (KeyboardMsg(wnd, p1, p2))
  964.                 return TRUE;
  965.             break;
  966.         case SHIFT_CHANGED:
  967.             ShiftChangedMsg(wnd, p1);
  968.             break;
  969.         case COMMAND:
  970.             if (CommandMsg(wnd, p1))
  971.                 return TRUE;
  972.             break;
  973.         case CLOSE_WINDOW:
  974.             CloseWindowMsg(wnd);
  975.             break;
  976.         default:
  977.             break;
  978.     }
  979.     return BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  980. }
  981. /* ------ save deleted text for the Undo command ------ */
  982. static void SaveDeletedText(WINDOW wnd, char *bbl, int len)
  983. {
  984.     wnd->DeletedLength = len;
  985.     if ((wnd->DeletedText=realloc(wnd->DeletedText,len))!=NULL)
  986.         memmove(wnd->DeletedText, bbl, len);
  987. }
  988. /* ---- cursor right key: right one character position ---- */
  989. static void Forward(WINDOW wnd)
  990. {
  991.     char *cc = CurrChar+1;
  992.     if (*cc == '\0')
  993.         return;
  994.     if (*CurrChar == '\n')    {
  995.         Home(wnd);
  996.         Downward(wnd);
  997.     }
  998.     else    {
  999.         wnd->CurrCol++;
  1000.         if (WndCol == ClientWidth(wnd))
  1001.             SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  1002.     }
  1003. }
  1004. /* ----- stick the moving cursor to the end of the line ---- */
  1005. static void StickEnd(WINDOW wnd)
  1006. {
  1007.     char *cp = TextLine(wnd, wnd->CurrLine);
  1008.     char *cp1 = strchr(cp, '\n');
  1009.     int len = cp1 ? (int) (cp1 - cp) : 0;
  1010.     wnd->CurrCol = min(len, wnd->CurrCol);
  1011.     if (wnd->wleft > wnd->CurrCol)    {
  1012.         wnd->wleft = max(0, wnd->CurrCol - 4);
  1013.         SendMessage(wnd, PAINT, 0, 0);
  1014.     }
  1015.     else if (wnd->CurrCol-wnd->wleft >= ClientWidth(wnd))    {
  1016.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  1017.         SendMessage(wnd, PAINT, 0, 0);
  1018.     }
  1019. }
  1020. /* --------- cursor down key: down one line --------- */
  1021. static void Downward(WINDOW wnd)
  1022. {
  1023.     if (isMultiLine(wnd) &&
  1024.             wnd->WndRow+wnd->wtop+1 < wnd->wlines)  {
  1025.         wnd->CurrLine++;
  1026.         if (wnd->WndRow == ClientHeight(wnd)-1)
  1027.             BaseWndProc(EDITBOX, wnd, SCROLL, TRUE, 0);
  1028.         else
  1029.             wnd->WndRow++;
  1030.         StickEnd(wnd);
  1031.     }
  1032. }
  1033. /* -------- cursor up key: up one line ------------ */
  1034. static void Upward(WINDOW wnd)
  1035. {
  1036.     if (isMultiLine(wnd) && wnd->CurrLine != 0)    {
  1037.         --wnd->CurrLine;
  1038.         if (wnd->WndRow == 0)
  1039.             BaseWndProc(EDITBOX, wnd, SCROLL, FALSE, 0);
  1040.         else
  1041.             --wnd->WndRow;
  1042.         StickEnd(wnd);
  1043.     }
  1044. }
  1045. /* ---- cursor left key: left one character position ---- */
  1046. static void Backward(WINDOW wnd)
  1047. {
  1048.     if (wnd->CurrCol)    {
  1049.         --wnd->CurrCol;
  1050.         if (wnd->CurrCol < wnd->wleft)
  1051.             SendMessage(wnd, HORIZSCROLL, FALSE, 0);
  1052.     }
  1053.     else if (isMultiLine(wnd) && wnd->CurrLine != 0)    {
  1054.         Upward(wnd);
  1055.         End(wnd);
  1056.     }
  1057. }
  1058. /* -------- End key: to end of line ------- */
  1059. static void End(WINDOW wnd)
  1060. {
  1061.     while (*CurrChar && *CurrChar != '\n')
  1062.         ++wnd->CurrCol;
  1063.     if (WndCol >= ClientWidth(wnd))    {
  1064.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  1065.         SendMessage(wnd, PAINT, 0, 0);
  1066.     }
  1067. }
  1068. /* -------- Home key: to beginning of line ------- */
  1069. static void Home(WINDOW wnd)
  1070. {
  1071.     wnd->CurrCol = 0;
  1072.     if (wnd->wleft != 0)    {
  1073.         wnd->wleft = 0;
  1074.         SendMessage(wnd, PAINT, 0, 0);
  1075.     }
  1076. }
  1077. /* -- Ctrl+cursor right key: to beginning of next word -- */
  1078. static void NextWord(WINDOW wnd)
  1079. {
  1080.     int savetop = wnd->wtop;
  1081.     int saveleft = wnd->wleft;
  1082.     ClearVisible(wnd);
  1083.     while (!isWhite(*CurrChar))    {
  1084.         char *cc = CurrChar+1;
  1085.         if (*cc == '\0')
  1086.             break;
  1087.         Forward(wnd);
  1088.     }
  1089.     while (isWhite(*CurrChar))    {
  1090.         char *cc = CurrChar+1;
  1091.         if (*cc == '\0')
  1092.             break;
  1093.         Forward(wnd);
  1094.     }
  1095.     SetVisible(wnd);
  1096.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  1097.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  1098.         SendMessage(wnd, PAINT, 0, 0);
  1099. }
  1100. /* -- Ctrl+cursor left key: to beginning of previous word -- */
  1101. static void PrevWord(WINDOW wnd)
  1102. {
  1103.     int savetop = wnd->wtop;
  1104.     int saveleft = wnd->wleft;
  1105.     ClearVisible(wnd);
  1106.     Backward(wnd);
  1107.     while (isWhite(*CurrChar))    {
  1108.         if (wnd->CurrLine == 0 && wnd->CurrCol == 0)
  1109.             break;
  1110.         Backward(wnd);
  1111.     }
  1112.     while (wnd->CurrCol != 0 && !isWhite(*CurrChar))
  1113.         Backward(wnd);
  1114.     if (isWhite(*CurrChar))
  1115.         Forward(wnd);
  1116.     SetVisible(wnd);
  1117.     if (wnd->wleft != saveleft)
  1118.         if (wnd->CurrCol >= saveleft)
  1119.             if (wnd->CurrCol - saveleft < ClientWidth(wnd))
  1120.                 wnd->wleft = saveleft;
  1121.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  1122.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  1123.         SendMessage(wnd, PAINT, 0, 0);
  1124. }
  1125. /* ----- modify text pointers from a specified position
  1126.                 by a specified plus or minus amount ----- */
  1127. static void ModTextPointers(WINDOW wnd, int lineno, int var)
  1128. {
  1129.     while (lineno < wnd->wlines)
  1130.         *((wnd->TextPointers) + lineno++) += var;
  1131. }
  1132.  
  1133.